/*
 * $Id: memory.c,v 1.12 2005-07-24 15:19:09 bacon Exp $
 */

#include <xp/bas/memory.h>

/*
typedef void* word;
#define wsize (xp_sizeof(word))
#define wmask (xp_sizeof(word) - 1)
*/

void* xp_memcpy_i (void* dst, const void* src, xp_size_t n)
{
	void* p = dst;
	void* e = (xp_byte_t*)dst + n;

	while (dst < e) {
		*(xp_byte_t*)dst = *(xp_byte_t*)src;
		dst = (xp_byte_t*)dst + 1;
		src = (xp_byte_t*)src + 1;
	}

	return p;

	/*
	 * the following code segment commented out is an example of
	 * optimization. but it cannot beat stock functions written
	 * mostly in assembly languages of the underlying architecture.
	 * for example, the glibc implementation of memcpy is 10 times faster.
	 */

	/*
	void* p = dst, * e;

	if (n == 0 || dst == src) return p;

	if (((xp_size_t)src | (xp_size_t)dst) & wmask) {
		if ((((xp_size_t)src ^ (xp_size_t)dst) & wmask) || (n < wsize)) {
			e = (xp_byte_t*)dst + n;
		}
		else {
			e = (xp_byte_t*)dst + (wsize - ((xp_size_t)src & wmask));
		}

		while (dst < e) {
			*(xp_byte_t*)dst = *(xp_byte_t*)src;
			dst = (xp_byte_t*)dst + 1;
			src = (xp_byte_t*)src + 1;
		}
	}

	e = (word*)dst + (n / wsize);
	while (dst < e) {
		*(word*)dst = *(word*)src;
		dst = (word*)dst + 1;
		src = (word*)src + 1;
	}

	e = (xp_byte_t*)dst + n;
	while (dst < e) {
		*(xp_byte_t*)dst = *(xp_byte_t*)src;
		dst = (xp_byte_t*)dst + 1;
		src = (xp_byte_t*)src + 1;
	}

	return p;
	*/
}

void* xp_memmove_i (void* dst, const void* src, xp_size_t n)
{
	void* p = dst;
	void* se = (xp_byte_t*)src + n;
	
	if (dst <= src || dst >= se) {
		while (src < se) {
			*(xp_byte_t*)dst = *(xp_byte_t*)src;
			dst = (xp_byte_t*)dst + 1;
			src = (xp_byte_t*)src + 1;
		}
	}
	else {
		dst = (xp_byte_t*)dst + n - 1;
		src = (xp_byte_t*)src + n - 1;

		while (dst >= p) {
			*(xp_byte_t*)dst = *(xp_byte_t*)src;
			dst = (xp_byte_t*)dst - 1;
			src = (xp_byte_t*)src - 1;
		}
	}

	return p;
}

void* xp_memset_i (void* dst, int val, xp_size_t n)
{
	void* p = dst;
	void* e = (xp_byte_t*)p + n;

	while (p < e) {
		*(xp_byte_t*)p = (xp_byte_t)val;
		p = (xp_byte_t*)p + 1;
	}

	return dst;
}

int xp_memcmp_i (const void* s1, const void* s2, xp_size_t n)
{
	const void* e;

	if (n == 0) return 0;

	e = (const xp_byte_t*)s1 + n - 1;
	while (s1 < e && *(xp_byte_t*)s1 == *(xp_byte_t*)s2) {
		s1 = (xp_byte_t*)s1 + 1;
		s2 = (xp_byte_t*)s2 + 1;
	}

	return *((xp_byte_t*)s1) - *((xp_byte_t*)s2);
}

void* xp_memchr_i (const void* s, int byte, xp_size_t n)
{
	const void* e = (const xp_byte_t*)s + n;

	while (s < e) {
		if (*(xp_byte_t*)s == (xp_byte_t)byte) return (void*)s;
		s = (xp_byte_t*)s + 1;
	}

	return XP_NULL;

}

void* xp_memrchr_i (const void* s, int byte, xp_size_t n)
{
	const void* e = (const xp_byte_t*)s + n - 1;

	while (e >= s) {
		if (*(xp_byte_t*)e == (xp_byte_t)byte) return (void*)e;
		e = (xp_byte_t*)e - 1;
	}

	return XP_NULL;
}

void* xp_memmem (	
	const void* haystack, xp_size_t hsz, const void* needle, xp_size_t nsz)
{
	xp_size_t i;

	if (nsz > hsz) return XP_NULL;
	for (i = hsz - nsz + 1; i > 0; i--)  {
		if (!xp_memcmp(haystack, needle, nsz)) return (void*)haystack;
		haystack = ((xp_byte_t*)haystack) + 1;
	}

	return XP_NULL;
}

xp_size_t xp_swab (void* dst, const void* src, xp_size_t n)
{
	xp_byte_t c;
	xp_byte_t* d = dst;
	const xp_byte_t* s = src;
	xp_size_t n2 = n >> 1;

	XP_REPEAT (n2, {c = *s++; *d++ = *s++; *d++ = c;});
	return n2 << 1;
}
